
// T K U P L 
// 1. 函数做一个约束 
// 2. 复杂的类型 提取出来当做泛型 
// 3. 使用: 如果是类 new的时候 不用传入泛型
// 4. 如果是一个方法  使用的时候 可以传入泛型 也可以不传
function getValue<T,U>(args : T|U):T | U{
  return args
}

getValue<number,string>(10)

// T : 只能是 cat dog pet 其中之一 

interface TypeAnimal{
  cat:string;
  dog:string;
  pet:'猪' // 类型推断 string
}
// keyof : 类型索引   代表类型里面的某一个值
type AnimalKeyOf = keyof TypeAnimal
const a :AnimalKeyOf ='pet'
// extends : 类型约束
function copy <T extends number | string | boolean>(arsg:T){
  // 如果是一个泛型类型 就不能赋值
}

class Animal<T>{

}

interface Team<T extends number | string | boolean>{
  keys:T
}

// 1. 可以用在 类  2. 方法  3. 可以用在接口上
// 2. 注意 : 如果一个类型是泛型 不能被赋值 只能做类型的约束
// extends : 类型约束 和 类的 extends 不一样 继承  
// keyof : 类型索引  变成某一个类型 
// extends : 一般是用在泛型里面的 做泛型扩展
// keyof : 可以用在任何地方

// 题目: 实现一个动物方法 参数是传入构造函数
// 有两个子类Bee 和 Lion  

class Animal1{
  getKeepName(animalName:string){
    console.log(animalName)
  }
}
class Line extends Animal1{

 
}
class Bee extends Animal1{
  call(){}
}
// 当使用 createInstanceAnimal(Line).getKeepName() // 打印出狮子
// 当使用 createInstanceAnimal(Bee).getKeepName() // 熊出没
// 结合泛型实现createInstanceAnimal方法 和实现具体的类
// new 类/方法 
// 
function createInstanceAnimal<T extends Animal1>(ClassName : new ()=>T){
  return new ClassName()
}

createInstanceAnimal(Bee).getKeepName('🐻')
createInstanceAnimal(Bee).call()